/*
 * Copyright (c) 2011, Yawning <yawninglol at gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   * Neither the name of the Mew Developers nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package yawning.mew.bear;

import yawning.mew.BuffsDebuffs;
import yawning.mew.MewProperty;
import yawning.mew.PropertiesBase;
import yawning.mew.BuffsDebuffs.Buff;
import yawning.mew.BuffsDebuffs.Debuff;
import yawning.mew.character.CharacterModel;
import yawning.mew.character.Clazz;
import yawning.mew.character.Glyph;
import yawning.mew.character.Talent;
import yawning.mew.character.TalentTree;
import yawning.mew.character.Toon;

public class BearModel extends CharacterModel {
	private static final MewProperty BUG_BERSERK_PROC_RATE = new MewProperty("Bug.BerserkProcRate", false);	// The Berserk tooltip is a lying peice of shit.
	private static final MewProperty BUG_VENGEANCE_DECAY = new MewProperty("Bug.VengeanceDecay", false);		// The forced 5% Vengeance decay was shipped broken for 4.3

	protected Toon mToon;
	protected PropertiesBase mConfig;
	protected BuffsDebuffs mBuffsDebuffs;
	protected BearStatLogic mLevelDep;

	protected BearModel(Toon t, PropertiesBase config) {
		super(t);
		mToon = t;
		mConfig = config;
		mBuffsDebuffs = new BuffsDebuffs(mConfig.getProperties());
		mLevelDep = new BearStatLogic(mStatLogic);
		calculateBaseStats();
	}

	@Override
	public double getAttackPower() {
		return((getAgility() - 10) * 2 + (getStrength() - 10) + mToon.attackPower + bonusAttackPower) * apMult;
	}

	// Bears have weapon speed forced to 2.5
    // Note: Can't just be done with this by super.getWeaponDamage() / mToon.getWeaponSpeed * 2500 because that breaks bonusWeaponDamage
	// BUG: Fury Swipes does not benefit from Bonus Weapon Damage (4.0.6 PTR)
    @Override
	public double getWeaponDamage() {
		return getWeaponDamage(false);
	}

	public double getWeaponDamage(boolean ignoreBonus) {
		double weaponDmg = 1 + (double)(mToon.weaponTop + mToon.weaponBottom) / 2  + getAttackPower() * mToon.weaponSpeed / 14000;
		weaponDmg = weaponDmg / mToon.weaponSpeed * 2500;
		if (ignoreBonus == false) weaponDmg += bonusWeaponDamage;

		return weaponDmg;
	}

	@Override
	public double getBaseWeaponSpeed() {
		return 2.5;
	}

	@Override
	public double getDodgeChance() {
		double dodge = super.getDodgeChance();
		dodge += mToon.getTalent(FERALSWIFTNESS) * 0.02;
		dodge += mToon.getTalent(NATURALREACTION) * 0.03;
		return Math.min(1.0, dodge);
	}

	// Talents
	private static final TalentTree FERAL_COMBAT = TalentTree.get(Clazz.DRUID, "Feral Combat");

	static final Talent FERALSWIFTNESS = Talent.getByName(Clazz.DRUID, "Feral Swiftness");
	static final Talent FUROR = Talent.getByName(Clazz.DRUID, "Furor");
	static final Talent PREDATORYSTRIKES = Talent.getByName(Clazz.DRUID, "Predatory Strikes");
	static final Talent INFECTEDWOUNDS = Talent.getByName(Clazz.DRUID, "Infected Wounds");
	static final Talent FURYSWIPES = Talent.getByName(Clazz.DRUID, "Fury Swipes");
	static final Talent PRIMALFURY = Talent.getByName(Clazz.DRUID, "Primal Fury");
	static final Talent FERALAGGRESSION = Talent.getByName(Clazz.DRUID, "Feral Aggression");
	static final Talent KINGOFTHEJUNGLE = Talent.getByName(Clazz.DRUID, "King of the Jungle");
	static final Talent FERALCHARGE = Talent.getByName(Clazz.DRUID, "Feral Charge");
	static final Talent STAMPEDE = Talent.getByName(Clazz.DRUID, "Stampede");
	static final Talent THICKHIDE = Talent.getByName(Clazz.DRUID, "Thick Hide");
	static final Talent LEADEROFTHEPACK = Talent.getByName(Clazz.DRUID, "Leader of the Pack");
	static final Talent BRUTALIMPACT = Talent.getByName(Clazz.DRUID, "Brutal Impact");
	static final Talent NURTURINGINSTINCT = Talent.getByName(Clazz.DRUID, "Nurturing Instinct");
	static final Talent PRIMALMADNESS = Talent.getByName(Clazz.DRUID, "Primal Madness");
	static final Talent SURVIVALINSTINCTS = Talent.getByName(Clazz.DRUID, "Survival Instincts");
	static final Talent ENDLESSCARNAGE = Talent.getByName(Clazz.DRUID, "Endless Carnage");
	static final Talent NATURALREACTION = Talent.getByName(Clazz.DRUID, "Natural Reaction");
	static final Talent BLOODINTHEWATER = Talent.getByName(Clazz.DRUID, "Blood in the Water");
	static final Talent RENDANDTEAR = Talent.getByName(Clazz.DRUID, "Rend and Tear");
	static final Talent PULVERIZE = Talent.getByName(Clazz.DRUID, "Pulverize");
	static final Talent BERSERK = Talent.getByName(Clazz.DRUID, "Berserk");

	static final Talent NATURALSHAPESHIFTER = Talent.getByName(Clazz.DRUID, "Natural Shapeshifter");
	static final Talent HEARTOFTHEWILD = Talent.getByName(Clazz.DRUID, "Heart of the Wild");
	static final Talent MASTERSHAPESHIFTER = Talent.getByName(Clazz.DRUID, "Master Shapeshifter");
	static final Talent PERSEVERANCE = Talent.getByName(Clazz.DRUID, "Perseverance");

	// Glyphs
	static final Glyph GLYPH_BERSERK = Glyph.getByName("Berserk");
	static final Glyph GLYPH_MANGLE = Glyph.getByName("Mangle");
	static final Glyph GLYPH_LACERATE = Glyph.getByName("Lacerate");
	static final Glyph GLYPH_FRENZIEDREGENERATION = Glyph.getByName("Frenzied Regeneration");
	static final Glyph GLYPH_MAUL = Glyph.getByName("Maul");
	static final Glyph GLYPH_FERALCHARGE = Glyph.getByName("Feral Charge");

	// Probabilities
	protected double pBerserkProc;
	protected double pPrimalFury;
	protected double pFurySwipes;
	protected double pInfectedWounds;
	protected double oocPPM;
	protected double pOoCProc;
	protected double pBonusLacerateCrit;
	protected double pSavageDefense = 0.5;

	// Multipliers
	protected double multThreatStance = 5.0;
	protected double multCrit;
	protected double multSpellCrit;
	protected double multHealCrit;
	protected double multPhysVuln;
	protected double multSpellVuln;
	protected double multDamageMult;
	protected double multMangle = 1.3;
	protected double multMangleGlyph;
	protected double multMaulRnT;
	protected double multBleedDarkIntent;
	protected double multFurySwipes = 3.10;
	protected double multTargetBaseArmor;
	protected double multMasterShapeshifter;
	protected double multSavageDefense = 0.35;
	protected double multLotPHeal = 0.04;
	protected double multFrenziedRegenerationHeal = 0.003;
	protected double multFrenziedRegenerationMaxHP = 1.3;	// The tooltip lies.
	protected double multFrenziedRegenerationGlyphIncHeal = 1.3;
	protected double multInfectedWounds;
	protected double multBarkskinDR = 0.8;
	protected double multBarkskin = 0.8; // 20% DR
	protected double multSurvivalInstinctsDR = 0.5;
	protected double multNaturalReactionDR;
	protected double multDemoralizingRoarDR = 0.9;	// 10% DR
	protected double multPerseveranceDR;

	// Durations
	protected int oocBuffDuration = 15;
	protected int enrageBuffDuration = 10;
	protected int enrageCDDuration = 60;
	protected int feralFFDebuffDuration = 60 * 5;
	protected int feralFFCDDuration = 6;
	protected int berserkBuffDuration;
	protected int berserkCDDuration = 180;
	protected int berserkProcBuffDuration = 5;
	protected int basePulverizeBuffDuration;		// Endless Carnage.
	protected int lacPulverizeBuffDuration = 10;	// Per Lacerate stack.
	protected int mangleDebuffDuration = 60;
	protected int mangleCDDuration = 6;
	protected int swipeCDDuration = 3;
	protected int feralChargeCDDuration = 15;
	protected int skullBashCDDuration;
	protected double stampedeBuffDuration = 8;
	protected int lacerateDebuffDuration = 15;
	protected int lacerateTickInterval = 3;
	protected int thrashDebuffDuration = 6;
	protected int thrashTickInterval = 2;
	protected int thrashCDDuration = 6;
	protected int demoralizingRoarDebuffDuration = 30;
	protected int furySwipesCDDuration = 3;
	protected int savageDefenseBuffDuration = 10;
	protected int maulCDDuration = 3;
	protected int infectedWoundsDebuffDuration = 12;
	protected int lotpCDDuration = 6;
	protected int barkskinBuffDuration = 12;
	protected int barkskinCDDuration = 60;
	protected int survivalInstinctsBuffDuration = 12;
	protected int survivalInstinctsCDDuration = 180;
	protected int frenziedRegenerationBuffDuration = 20;
	protected int frenziedRegenerationCDDuration = 180;
	protected int bashCDDuration;
	protected double bashStunDuration;

	// Costs.
	protected int feralChargeCost = 5;
	protected int demoralizingRoarCost = 10;
	protected int skullBashCost = 15;
	protected int lacerateCost = 15;
	protected int pulverizeCost = 15;
	protected int maulCost = 30;
	protected int thrashCost = 25;
	protected int swipeCost = 15;
	protected int mangleCost = 15;
	protected int bashCost = 10;

	// Misc values.
	protected int nrFeralFFStacksPerCast;
	protected int primalMadnessRage;
	protected int naturalReactionRage;

	// Set bonuses.
	protected double tier_11_2pc_lacerateDoTMult;
	protected double tier_12_2pc_damageMult = 0.1;
	protected double tier_12_2pc_dotDuration = 4;
	protected double tier_12_2pc_dotTickInterval = 2;
	protected double tier_12_4pc_bonusDodge = 0.1;
	protected double tier_12_4pc_buffDuration = 12;

	// Bugs
	protected boolean bug_pooledProcEffects;
	protected boolean bug_vengeanceDecay;

	private void calculateBaseStats() {
		// Agi, Str, AP.
		double statMult = mBuffsDebuffs.isBuff(Buff.STATMULT) ? 1.05 : 1;
		multiplyStrength(statMult);
		multiplyStamina(statMult);
		multiplyAgility(statMult);
		multiplyIntellect(statMult);

		int buffAgiStr = mBuffsDebuffs.isBuff(Buff.AGISTR) ? mStatLogic.getBuffAgiStr(): 0;
		addAgility(buffAgiStr);
		addStrength(buffAgiStr);

		addStamina(mBuffsDebuffs.isBuff(Buff.STAMINA) ? mStatLogic.getBuffStamina() : 0);
		addArmor(mBuffsDebuffs.isBuff(Buff.ARMOR) ? mStatLogic.getBuffArmor() : 0);

		multiplyAttackPower(mToon.mTalentSpec == FERAL_COMBAT ? 1.25 : 1);
		multiplyAttackPower(mBuffsDebuffs.isBuff(Buff.APMULT) ? 1.2 : 1);
		multiplyStamina(mToon.getTalent(HEARTOFTHEWILD) * 0.02 + 1);

		// Bear form
		multiplyStamina(1.2);
		multiplyStamina(mToon.isArmorSpec ? 1.05 : 1);
		multiplyBaseArmor(2.2);
		multiplyBaseArmor(1 + mToon.getTalent(THICKHIDE) * 0.26);

		// Crit
		addMeleeCrit(mStatLogic.getBasePhysicalCrit());
		addMeleeCrit(mBuffsDebuffs.isBuff(Buff.CRIT) ? 0.05 : 0);
		addSpellCrit(mStatLogic.getBaseSpellCrit());
		addSpellCrit(mBuffsDebuffs.isBuff(Buff.CRIT) ? 0.05 : 0);
		addHealCrit(mStatLogic.getBaseSpellCrit());
		addHealCrit(mBuffsDebuffs.isBuff(Buff.CRIT) ? 0.05 : 0);
		addSpellCrit(mBuffsDebuffs.isDebuff(Debuff.SPELLCRIT) ? 0.05 : 0);

		// Haste
		multiplyHaste(mBuffsDebuffs.isBuff(Buff.DARKINTENT) ? 1.03 : 1);
		multiplyMeleeHaste(mBuffsDebuffs.isBuff(Buff.MELEEHASTE) ? 1.1 : 1);
		multiplySpellHaste(mBuffsDebuffs.isBuff(Buff.SPELLHASTE) ? 1.05 : 1);

		// Probabilities
		pPrimalFury = mToon.getTalent(PRIMALFURY) * 0.5;
		pFurySwipes = mToon.getTalent(FURYSWIPES) * 0.05;
		oocPPM = 3.5;
		pOoCProc = oocPPM * (getBaseWeaponSpeed() / 60);
		pBerserkProc = (mToon.getTalent(BERSERK) == 1) ? 0.5 : 0;
		pInfectedWounds = (mToon.getTalent(INFECTEDWOUNDS) > 0) ? 1 : 0;
		pBonusLacerateCrit = (mToon.hasGlyph(GLYPH_LACERATE)) ? 0.05 : 0;

		// Multipliers
		multCrit = physicalCritMult;
		multSpellCrit = spellCritMult;
		multHealCrit = healCritMult;
		multPhysVuln = (mBuffsDebuffs.isDebuff(Debuff.PHYSVULN)) ? 1.04 : 1;
		multSpellVuln = (mBuffsDebuffs.isDebuff(Debuff.SPELLVULN)) ? 1.08 : 1;
		multDamageMult = (mBuffsDebuffs.isBuff(Buff.DAMAGEMULT)) ? 1.03 : 1;
		double bonusRnT = mToon.getTalent(RENDANDTEAR) * 0.07;
		bonusRnT -= (mToon.getTalent(RENDANDTEAR) > 1) ? 0.01 : 0;
		multMaulRnT = (mToon.getTalent(RENDANDTEAR) > 0) ? 1 + bonusRnT : 1;
		multMangleGlyph = (mToon.hasGlyph(GLYPH_MANGLE)) ? 1.1 : 1;
		multBleedDarkIntent = ((mBuffsDebuffs.isBuff(Buff.DARKINTENT)) ? 1.03 : 1);
		multMasterShapeshifter = (mToon.getTalent(MASTERSHAPESHIFTER) > 0) ? 1.04 : 1;
		multInfectedWounds = 1 + mToon.getTalent(INFECTEDWOUNDS) * 0.1;
		multNaturalReactionDR = 1.0f - mToon.getTalent(NATURALREACTION) * 0.09;
		multPerseveranceDR = 1.0f - mToon.getTalent(PERSEVERANCE) * 0.02;
		multiplyIncPhysicalDamage(multNaturalReactionDR);
		multiplyIncMagicDamage(multNaturalReactionDR);
		multiplyIncMagicDamage(multPerseveranceDR);
		multiplyIncPhysicalDamage(mBuffsDebuffs.isBuff(Buff.PHYSDMGINC) ? 0.9 : 1);

		// Durations
		berserkBuffDuration = 15 + (mToon.hasGlyph(GLYPH_BERSERK) ? 10 : 0);
		basePulverizeBuffDuration = mToon.getTalent(ENDLESSCARNAGE) * 4;
		stampedeBuffDuration = (mToon.getTalent(STAMPEDE) > 0) ? 8 : 0;
		skullBashCDDuration = 60 - (mToon.getTalent(BRUTALIMPACT) * 25);
		feralChargeCDDuration = 30 - (mToon.hasGlyph(GLYPH_FERALCHARGE) ? 1 : 0);
		bashStunDuration = 5 + (mToon.getTalent(BRUTALIMPACT) * 0.5);
		bashCDDuration = 60 - (mToon.getTalent(BRUTALIMPACT) * 5);

		// Misc.
		nrFeralFFStacksPerCast = 1 + mToon.getTalent(FERALAGGRESSION);
		primalMadnessRage = mToon.getTalent(PRIMALMADNESS) * 6;
		naturalReactionRage = mToon.getTalent(NATURALREACTION);
		naturalReactionRage += (mToon.getTalent(NATURALREACTION) == 2) ? 2 : 0;
		addMobCrit(-(mToon.getTalent(THICKHIDE) * 0.02));

		// Set/Equipment bonuses.
		//
		// PvP:
		// Gloves - Reduces the energy and rage cost of your Skull Bash by 10.
		//
		// Tier 11:
		// Druid T11 Feral 2P Bonus - Increases the periodic damage done by your Rake and Lacerate abilities by 10%.
		// Druid T11 Feral 4P Bonus - +50% SI Duration
		// Druid T11 Feral 4P Bonus - Each time you use Mangle (Cat) you gain a 1% increase to attack power for 30 sec stacking up to 3 times, and the duration of your Survival Instinct ability is increased by 50%.
		// Druid T12 Feral 2P Bonus - Your attacks with Mangle, Maul, and Shred deal 10% additional damage as Fire damage over 4 sec.
		// Druid T12 Feral 4P Bonus - Your finishing moves have a 20% chance per combo point to extend the duration of Berserk by 2 + (20 * ComboPoints) sec and when your Barkskin ability expires you gain an additional 10% chance to dodge for 12 sec.
		// Druid T13 Feral 2P Bonus - Pulverize now also grants your Mangle (Bear) critical strikes a 100% chance to trigger Savage Defense, and your Blood in the Water talent now causes Ferocious Bite to refresh the duration of your Rip on targets with 60% or less health.
		// Druid T13 Feral 4P Bonus - Frenzied Regeneration also affects all raid and party members. This effect cannot be triggered if you have been in Bear Form for less than 15 sec. In addition, your Stampede talent now grants two charges after using Feral Charge (Cat).
		//
		skullBashCost -= mToon.pvp_gloves ? 10 : 0;
		tier_11_2pc_lacerateDoTMult = mToon.tier_11_2pc ? 1.1 : 1.0;
		survivalInstinctsBuffDuration += mToon.tier_11_4pc ? 6 : 0;

		// Blizzard bugs
		if (mConfig.getBool(BUG_BERSERK_PROC_RATE) && pBerserkProc > 0) pBerserkProc = 0.3;
		bug_pooledProcEffects = mConfig.getBool(BUG_POOLED_PROC_EFFECTS);
		bug_vengeanceDecay = mConfig.getBool(BUG_VENGEANCE_DECAY);
	}

	public final double getSavageDefenseMastery() {
		return 1 + getMastery() * 0.04;
	}
}
